﻿// Inner Fire 游戏引擎库
// Pipeline管理类
//
// Copyright (c) 2024 by 尔西大帝. All rights reserved.
//
// 这个类提供Pipeline的快捷操作。
//
// Author: 尔西大帝
// Email: 2670613871@qq.com
// Created: 2024-12-06

#include "dx_pipeline.h"
#include <dx/graphics/dx_graphics.h>
#include <dx/texture/ssao.h>
#include <game/resource/assets.h>
#include <game/resource/shader.h>

namespace ifire::dx {

// 用于快速绑定Shader，使项目易读
#define SHADERS_ARGS_(name)                                                    \
  {reinterpret_cast<BYTE*>(shaders_[name]->GetBufferPointer()),                \
      shaders_[name]->GetBufferSize()}

DxPipeline::DxPipeline(DxGraphics* dx) : DxModule(dx) {}

void DxPipeline::BuildShaderAndInputLayout(
    const D3D_SHADER_MACRO* debug_defines) {
  // 设置预制值
  auto ssao_enable = dx_->GetPostProcessing().GetSsaoEnable();
  const D3D_SHADER_MACRO defines[] = {
      "FOG", "1",                                                   // 雾效
      ssao_enable ? "SSAO_ENABLE" : NULL, ssao_enable ? "1" : NULL, // SSAO
      NULL, NULL // 这为什么要两个NULL？用来对齐？
  };
  const D3D_SHADER_MACRO waveDefines[] = {"DISPLACEMENT_MAP", "1", NULL, NULL};
  // 设置alpha_test
  const D3D_SHADER_MACRO alpha_test[] = {
      "FOG", "1", "ALPHA_TEST", "1", NULL, NULL};
  // 设置alpha_test
  const D3D_SHADER_MACRO skinned_alpha_test[] = {
      "SKINNED_ALPHA_TEST", "1", NULL, NULL};
  // 用于蒙皮骨骼
  const D3D_SHADER_MACRO skinnedDefines[] = {"SKINNED", "1", NULL, NULL};
  // 用于粒子系统里面的分类
  const D3D_SHADER_MACRO point_defines[] = {"POINT", "1", NULL, NULL};
  const D3D_SHADER_MACRO line_defines[] = {"LINE", "1", NULL, NULL};
  const D3D_SHADER_MACRO mesh_defines[] = {"MESH", "1", NULL, NULL};

  // 依次加载Shader
  for (auto& i : game::Assets::GetInstance().Shaders()) {
    if (i->is_system) {
      shaders_[i->name.c_str()] = DxUtils::CompileOrLoadShader(
          i->filename.c_str(), i->GetD3DDefines(), i->entry, i->target);
    }
  }

  input_layout_ = {
      {"POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0,
          D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0},
      {"NORMAL", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 12,
          D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0},
      {"TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 24,
          D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0},
      {"TANGENT", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 32,
          D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0},
  };

  skinned_input_layout_ = {//
      {"POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0,
          D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0},
      {"NORMAL", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 12,
          D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0},
      {"TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 24,
          D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0},
      {"TANGENT", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 32,
          D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0},
      {"WEIGHTS", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, 44,
          D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0},
      {"BONEINDICES", 0, DXGI_FORMAT_R16G16B16A16_UINT, 0, 60,
          D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0}};

  tree_sprite_input_layout_ = {
      {"POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0,
          D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0},
      {"SIZE", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 12,
          D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0},
  };

  ui_input_layout_ = {//
      {"POSITION", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 0,
          D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0},
      {"TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 8,
          D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0}};
}

void DxPipeline::BuildPipelineStates() {

  // TIP1:
  // PSO的创建非常消耗性能。所以最好在初始化的时候就创建。
  // TIP2:
  // 尽可能减少改变PSO状态的次数，如果能用一个PSO绘制出所有的物体，绝不用第2个。

  //
  // 用于不透明/透明的对象，这是一切的基础，最初只创建这些Pipeline，其它按需要创建
  //
  CreateOpaque();
  CreateTransparent();
  CreateAlpha();
  CreateShadow();
  CreateSky();
  CreateUIImage();
  CreateMapBlock();

  // 按需创建
  if (dx_->GetPostProcessing().GetSsaoEnable()) {
    CreateDrawNormals();
    CreateSsao();
  }
  if (dx_->IsSobelEnable()) {
    CreateComposite();
    CreateSobel();
  }

  //
  // CreateDebug();
  // CreateTreeSprites();
  // CreateWaves();
  //
  CreateParticle();
}

void DxPipeline::CreateOpaque() {
  ZeroMemory(&opaque_desc, sizeof(D3D12_GRAPHICS_PIPELINE_STATE_DESC));

  opaque_desc.InputLayout = {
      input_layout_.data(), static_cast<UINT>(input_layout_.size())};
  opaque_desc.pRootSignature = dx_->GetRootsign().mStandard.Get();
  opaque_desc.VS = SHADERS_ARGS_(STANDARD_VS);
  opaque_desc.PS = SHADERS_ARGS_(OPAQUE_PS);
  opaque_desc.RasterizerState = CD3DX12_RASTERIZER_DESC(D3D12_DEFAULT);
  // opaque_desc.RasterizerState.FillMode = D3D12_FILL_MODE_WIREFRAME;
  opaque_desc.BlendState = CD3DX12_BLEND_DESC(D3D12_DEFAULT);
  opaque_desc.DepthStencilState = CD3DX12_DEPTH_STENCIL_DESC(D3D12_DEFAULT);
  opaque_desc.SampleMask = UINT_MAX;
  opaque_desc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE;
  opaque_desc.NumRenderTargets = 1;
  opaque_desc.RTVFormats[0] = BACK_BUFFER_FORMAT;
  opaque_desc.SampleDesc.Count = DxUtils::GetMsaaSampleCount();
  opaque_desc.SampleDesc.Quality = DxUtils::GetMsaaSampleQuality();
  opaque_desc.DSVFormat = DEPTH_STENCIL_FORMAT;
  // 用于不透明的对象
  HASSERT(dx_->Device()->CreateGraphicsPipelineState(
      &opaque_desc, IID_PPV_ARGS(&pipelines_["Opaque"])));

  //
  // 不透明的对象(蒙皮骨骼）
  //
  skinned_desc = opaque_desc;
  skinned_desc.InputLayout = {
      skinned_input_layout_.data(), (UINT)skinned_input_layout_.size()};
  skinned_desc.VS = SHADERS_ARGS_(SKINNED_VS);
  skinned_desc.PS = SHADERS_ARGS_(OPAQUE_PS);
  HASSERT(dx_->Device()->CreateGraphicsPipelineState(
      &skinned_desc, IID_PPV_ARGS(&pipelines_["SkinnedOpaque"])));
}

void DxPipeline::CreateTransparent() {
  //
  // 用于透明的对象
  //
  transparent_desc = opaque_desc;
  D3D12_RENDER_TARGET_BLEND_DESC general_trans{};
  general_trans.BlendEnable = true;
  general_trans.LogicOpEnable = false;
  general_trans.SrcBlend = D3D12_BLEND_SRC_ALPHA;
  general_trans.DestBlend = D3D12_BLEND_INV_SRC_ALPHA;
  general_trans.BlendOp = D3D12_BLEND_OP_ADD;
  general_trans.SrcBlendAlpha = D3D12_BLEND_ONE;
  general_trans.DestBlendAlpha = D3D12_BLEND_ZERO;
  general_trans.BlendOpAlpha = D3D12_BLEND_OP_ADD;
  general_trans.LogicOp = D3D12_LOGIC_OP_NOOP;
  general_trans.RenderTargetWriteMask = D3D12_COLOR_WRITE_ENABLE_ALL;
  transparent_desc.BlendState.RenderTarget[0] = general_trans;

  transparent_desc.DepthStencilState.DepthWriteMask =
      D3D12_DEPTH_WRITE_MASK_ZERO;                       // 禁用深度写入
  transparent_desc.DepthStencilState.DepthEnable = TRUE; // 保持深度测试启用
  HASSERT(dx_->Device()->CreateGraphicsPipelineState(
      &transparent_desc, IID_PPV_ARGS(&pipelines_["Transparent"])));

  // 用于透明的对象（蒙皮骨骼）
  D3D12_GRAPHICS_PIPELINE_STATE_DESC skinnedTransparent = transparent_desc;
  skinnedTransparent.InputLayout = {
      skinned_input_layout_.data(), (UINT)skinned_input_layout_.size()};
  skinnedTransparent.VS = SHADERS_ARGS_(SKINNED_VS);
  HASSERT(dx_->Device()->CreateGraphicsPipelineState(
      &skinnedTransparent, IID_PPV_ARGS(&pipelines_["SkinnedTransparent"])));
}

void DxPipeline::CreateOpaqueWire() {
  // 用于线框模式
  D3D12_GRAPHICS_PIPELINE_STATE_DESC wire_desc = opaque_desc;
  wire_desc.RasterizerState.FillMode = D3D12_FILL_MODE_WIREFRAME;
  HASSERT(dx_->Device()->CreateGraphicsPipelineState(
      &wire_desc, IID_PPV_ARGS(&pipelines_["OpaqueWire"])));

  // 用于线框模式(蒙皮骨骼）
  D3D12_GRAPHICS_PIPELINE_STATE_DESC skin_wire_desc = skinned_desc;
  skin_wire_desc.RasterizerState.FillMode = D3D12_FILL_MODE_WIREFRAME;
  HASSERT(dx_->Device()->CreateGraphicsPipelineState(
      &skin_wire_desc, IID_PPV_ARGS(&pipelines_["SkinnedOpaqueWire"])));
}

void DxPipeline::CreateAlphaTest() {
  //
  // 用于alpha_test
  //
  D3D12_GRAPHICS_PIPELINE_STATE_DESC alphaTestedPsoDesc = opaque_desc;
  alphaTestedPsoDesc.PS = SHADERS_ARGS_(ALPHA_TEST_PS);
  alphaTestedPsoDesc.RasterizerState.CullMode = D3D12_CULL_MODE_NONE;
  HASSERT(dx_->Device()->CreateGraphicsPipelineState(
      &alphaTestedPsoDesc, IID_PPV_ARGS(&pipelines_["AlphaTested"])));

  //
  // 用于alpha_test(蒙皮骨骼）
  //
  D3D12_GRAPHICS_PIPELINE_STATE_DESC skinnedAlpha = skinned_desc;
  skinnedAlpha.PS = SHADERS_ARGS_(ALPHA_TEST_PS);
  skinnedAlpha.RasterizerState.CullMode = D3D12_CULL_MODE_NONE;
  HASSERT(dx_->Device()->CreateGraphicsPipelineState(
      &skinnedAlpha, IID_PPV_ARGS(&pipelines_["SkinnedAlphaTested"])));
}

void DxPipeline::CreateShadow() {
  //
  // 用于绘制阴影贴图
  //
  D3D12_GRAPHICS_PIPELINE_STATE_DESC shadow_desc = opaque_desc;
  shadow_desc.RasterizerState.DepthBias = 100000;
  shadow_desc.RasterizerState.DepthBiasClamp = 0.0f;
  shadow_desc.RasterizerState.SlopeScaledDepthBias = 1.0f;
  shadow_desc.VS = SHADERS_ARGS_(SHADOW_VS);
  shadow_desc.PS = SHADERS_ARGS_(SHADOW_PS);

  // 阴影贴图不需要Render Target.
  shadow_desc.RTVFormats[0] = DXGI_FORMAT_UNKNOWN;
  shadow_desc.NumRenderTargets = 0;
  HASSERT(dx_->Device()->CreateGraphicsPipelineState(
      &shadow_desc, IID_PPV_ARGS(&pipelines_["ShadowOpaque"])));

  // 阴影贴图（蒙皮骨骼）
  D3D12_GRAPHICS_PIPELINE_STATE_DESC skinnedSmapPsoDesc = shadow_desc;
  skinnedSmapPsoDesc.InputLayout = {
      skinned_input_layout_.data(), (UINT)skinned_input_layout_.size()};
  skinnedSmapPsoDesc.VS = SHADERS_ARGS_(SKINNED_SHADOW_VS);
  skinnedSmapPsoDesc.PS = SHADERS_ARGS_(SHADOW_PS);
  HASSERT(dx_->Device()->CreateGraphicsPipelineState(
      &skinnedSmapPsoDesc, IID_PPV_ARGS(&pipelines_["SkinnedShadowOpaque"])));
}

void DxPipeline::CreateSky() {
  //
  // 用于绘制天空盒
  //
  D3D12_GRAPHICS_PIPELINE_STATE_DESC sky_desc = opaque_desc;
  // 相机位于天空球内部，因此须关闭剔除功能。
  sky_desc.RasterizerState.CullMode = D3D12_CULL_MODE_NONE;
  // 确保深度函数是LESS_EQUAL（小于等于）而不仅仅是LESS（小于）。
  // 否则，当深度缓冲区被清除为1时，z = 1（NDC）处的标准化深度值将
  // 无法通过深度测试。
  sky_desc.DepthStencilState.DepthFunc = D3D12_COMPARISON_FUNC_LESS_EQUAL;
  sky_desc.VS = SHADERS_ARGS_(SKYBOX_VS);
  sky_desc.PS = SHADERS_ARGS_(SKYBOX_PS);
  HASSERT(dx_->Device()->CreateGraphicsPipelineState(
      &sky_desc, IID_PPV_ARGS(&pipelines_["Sky"])));
}

void DxPipeline::CreateDebug() {
  //
  // 用于绘制调试层
  //
  D3D12_GRAPHICS_PIPELINE_STATE_DESC debugPsoDesc = opaque_desc;
  debugPsoDesc.VS = SHADERS_ARGS_(SHADOW_DEBUG_VS);
  debugPsoDesc.PS = SHADERS_ARGS_(SHADOW_DEBUG_PS);
  HASSERT(dx_->Device()->CreateGraphicsPipelineState(
      &debugPsoDesc, IID_PPV_ARGS(&pipelines_["Debug"])));
}

void DxPipeline::CreateDrawNormals() {
  //
  // 用于绘制观察空间法线
  //
  D3D12_GRAPHICS_PIPELINE_STATE_DESC drawNormalsDesc = opaque_desc;
  drawNormalsDesc.VS = SHADERS_ARGS_(DRAW_NORMALS_VS);
  drawNormalsDesc.PS = SHADERS_ARGS_(DRAW_NORMALS_PS);
  drawNormalsDesc.RTVFormats[0] = Ssao::NormalMapFormat;
  drawNormalsDesc.SampleDesc.Count = 1;
  drawNormalsDesc.SampleDesc.Quality = 0;
  drawNormalsDesc.DSVFormat = DEPTH_STENCIL_FORMAT;
  HASSERT(dx_->Device()->CreateGraphicsPipelineState(
      &drawNormalsDesc, IID_PPV_ARGS(&pipelines_["DrawNormals"])));

  // 用于绘制观察空间法线（蒙皮骨骼）
  D3D12_GRAPHICS_PIPELINE_STATE_DESC skinnedDrawNormalsDesc = drawNormalsDesc;
  skinnedDrawNormalsDesc.InputLayout = {
      skinned_input_layout_.data(), (UINT)skinned_input_layout_.size()};
  skinnedDrawNormalsDesc.VS = SHADERS_ARGS_(SKINNED_DRAW_NORMALS_VS);
  skinnedDrawNormalsDesc.PS = SHADERS_ARGS_(DRAW_NORMALS_PS);
  HASSERT(dx_->Device()->CreateGraphicsPipelineState(&skinnedDrawNormalsDesc,
      IID_PPV_ARGS(&pipelines_["SkinnedDrawNormals"])));
}

void DxPipeline::CreateSsao() {
  //
  // 用于SSAO.
  //
  D3D12_GRAPHICS_PIPELINE_STATE_DESC ssaoPsoDesc = opaque_desc;
  ssaoPsoDesc.InputLayout = {nullptr, 0};
  ssaoPsoDesc.pRootSignature = dx_->GetRootsign().mSsao.Get();
  ssaoPsoDesc.VS = SHADERS_ARGS_(SSAO_VS);
  ssaoPsoDesc.PS = SHADERS_ARGS_(SSAO_PS);
  ssaoPsoDesc.DepthStencilState.DepthEnable = false; // SSAO不需要深度缓冲
  ssaoPsoDesc.DepthStencilState.DepthWriteMask = D3D12_DEPTH_WRITE_MASK_ZERO;
  ssaoPsoDesc.RTVFormats[0] = Ssao::AmbientMapFormat;
  ssaoPsoDesc.SampleDesc.Count = 1;
  ssaoPsoDesc.SampleDesc.Quality = 0;
  ssaoPsoDesc.DSVFormat = DXGI_FORMAT_UNKNOWN;
  HASSERT(dx_->Device()->CreateGraphicsPipelineState(
      &ssaoPsoDesc, IID_PPV_ARGS(&pipelines_["Ssao"])));

  //
  // 用于SSAO模糊
  //
  D3D12_GRAPHICS_PIPELINE_STATE_DESC ssaoBlurPsoDesc = ssaoPsoDesc;
  ssaoBlurPsoDesc.VS = SHADERS_ARGS_(SSAO_BLUR_VS);
  ssaoBlurPsoDesc.PS = SHADERS_ARGS_(SSAO_BLUR_PS);
  HASSERT(dx_->Device()->CreateGraphicsPipelineState(
      &ssaoBlurPsoDesc, IID_PPV_ARGS(&pipelines_["SsaoBlur"])));
}

void DxPipeline::CreateTreeSprites() {
  //
  // 用于树公告牌
  //
  D3D12_GRAPHICS_PIPELINE_STATE_DESC treeSpritePsoDesc = opaque_desc;
  treeSpritePsoDesc.VS = SHADERS_ARGS_(TREE_SPRITE_VS);
  treeSpritePsoDesc.GS = SHADERS_ARGS_(TREE_SPRITE_GS);
  treeSpritePsoDesc.PS = SHADERS_ARGS_(TREE_SPRITE_PS);
  treeSpritePsoDesc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_POINT;
  treeSpritePsoDesc.InputLayout = {
      tree_sprite_input_layout_.data(), (UINT)tree_sprite_input_layout_.size()};
  treeSpritePsoDesc.RasterizerState.CullMode = D3D12_CULL_MODE_NONE;

  HASSERT(dx_->Device()->CreateGraphicsPipelineState(
      &treeSpritePsoDesc, IID_PPV_ARGS(&pipelines_["TreeSprites"])));
}

void DxPipeline::CreateComposite() {
  //
  // 用于后处理合成
  //
  D3D12_GRAPHICS_PIPELINE_STATE_DESC compositePSO = opaque_desc;
  compositePSO.pRootSignature = dx_->GetRootsign().mPostProcessing.Get();
  compositePSO.DepthStencilState.DepthEnable = false;
  compositePSO.DepthStencilState.DepthWriteMask = D3D12_DEPTH_WRITE_MASK_ZERO;
  compositePSO.DepthStencilState.DepthFunc = D3D12_COMPARISON_FUNC_ALWAYS;
  compositePSO.VS = SHADERS_ARGS_(COMPOSITE_VS);
  compositePSO.PS = SHADERS_ARGS_(COMPOSITE_PS);
  HASSERT(dx_->Device()->CreateGraphicsPipelineState(
      &compositePSO, IID_PPV_ARGS(&pipelines_["Composite"])));
}

void DxPipeline::CreateWaves() {
  //
  // 用于绘制波浪
  //
  D3D12_GRAPHICS_PIPELINE_STATE_DESC wavesRenderPSO = transparent_desc;
  D3D12_RENDER_TARGET_BLEND_DESC water_trans{};
  water_trans.BlendEnable = true;
  water_trans.LogicOpEnable = false;
  water_trans.SrcBlend = D3D12_BLEND_SRC_ALPHA;
  water_trans.DestBlend = D3D12_BLEND_INV_SRC_ALPHA;
  water_trans.BlendOp = D3D12_BLEND_OP_ADD;
  water_trans.SrcBlendAlpha = D3D12_BLEND_ONE;
  water_trans.DestBlendAlpha = D3D12_BLEND_ZERO;
  water_trans.BlendOpAlpha = D3D12_BLEND_OP_ADD;
  water_trans.LogicOp = D3D12_LOGIC_OP_NOOP;
  water_trans.RenderTargetWriteMask = D3D12_COLOR_WRITE_ENABLE_ALL;
  wavesRenderPSO.BlendState.RenderTarget[0] = water_trans;
  wavesRenderPSO.VS = SHADERS_ARGS_(WAVES_VS);
  HASSERT(dx_->Device()->CreateGraphicsPipelineState(
      &wavesRenderPSO, IID_PPV_ARGS(&pipelines_["WavesRender"])));

  //
  // 用于扰动波浪
  //
  D3D12_COMPUTE_PIPELINE_STATE_DESC wavesDisturbPSO = {};
  wavesDisturbPSO.pRootSignature = dx_->GetRootsign().mWaves.Get();
  wavesDisturbPSO.CS = SHADERS_ARGS_(WAVES_DISTURB_CS);
  wavesDisturbPSO.Flags = D3D12_PIPELINE_STATE_FLAG_NONE;
  HASSERT(dx_->Device()->CreateComputePipelineState(
      &wavesDisturbPSO, IID_PPV_ARGS(&pipelines_["WavesDisturb"])));

  //
  // 用于更新波浪
  //
  D3D12_COMPUTE_PIPELINE_STATE_DESC wavesUpdatePSO = {};
  wavesUpdatePSO.pRootSignature = dx_->GetRootsign().mWaves.Get();
  wavesUpdatePSO.CS = SHADERS_ARGS_(WAVES_UPDATE_CS);
  wavesUpdatePSO.Flags = D3D12_PIPELINE_STATE_FLAG_NONE;
  HASSERT(dx_->Device()->CreateComputePipelineState(
      &wavesUpdatePSO, IID_PPV_ARGS(&pipelines_["WavesUpdate"])));
}

void DxPipeline::CreateSobel() {
  //
  // 用于索贝尔算子
  //
  D3D12_COMPUTE_PIPELINE_STATE_DESC sobelPSO = {};
  sobelPSO.pRootSignature = dx_->GetRootsign().mPostProcessing.Get();
  sobelPSO.CS = SHADERS_ARGS_(SOBEL_CS);
  sobelPSO.Flags = D3D12_PIPELINE_STATE_FLAG_NONE;
  HASSERT(dx_->Device()->CreateComputePipelineState(
      &sobelPSO, IID_PPV_ARGS(&pipelines_["Sobel"])));
}

void DxPipeline::CreateUIImage() {
  //
  // 用于UI的图片
  //
  D3D12_GRAPHICS_PIPELINE_STATE_DESC ui_image_desc = opaque_desc;
  ui_image_desc.pRootSignature = dx_->GetRootsign().mUI.Get();
  ui_image_desc.VS = SHADERS_ARGS_(UI_IMAGE_VS);
  ui_image_desc.PS = SHADERS_ARGS_(UI_IMAGE_PS);
  ui_image_desc.InputLayout = {
      ui_input_layout_.data(), (UINT)ui_input_layout_.size()};
  ui_image_desc.RasterizerState.CullMode = D3D12_CULL_MODE_NONE;
  HASSERT(dx_->Device()->CreateGraphicsPipelineState(
      &ui_image_desc, IID_PPV_ARGS(&pipelines_["UIImage"])));
}

void DxPipeline::CreateMapBlock() {
  //
  // 用于地图Block的图片(共用粒子的root）
  //
  D3D12_GRAPHICS_PIPELINE_STATE_DESC map_block_desc = opaque_desc;
  map_block_desc.pRootSignature = dx_->GetRootsign().mParticle.Get();
  map_block_desc.VS = SHADERS_ARGS_(MAP_BLOCK_VS);
  map_block_desc.PS = SHADERS_ARGS_(MAP_BLOCK_PS);
  map_block_desc.InputLayout = {
      input_layout_.data(), (UINT)input_layout_.size()};
  HASSERT(dx_->Device()->CreateGraphicsPipelineState(
      &map_block_desc, IID_PPV_ARGS(&pipelines_["MapBlock"])));
}

void DxPipeline::CreateParticle() {
  //
  // 用于Particle（粒子）的图片
  //
  D3D12_GRAPHICS_PIPELINE_STATE_DESC particle_desc = opaque_desc;
  particle_desc.pRootSignature = dx_->GetRootsign().mParticle.Get();
  particle_desc.VS = SHADERS_ARGS_(PARTICLE_VS);
  particle_desc.PS = SHADERS_ARGS_(PARTICLE_PS);

  // 这个让项目始终在最前面
  D3D12_DEPTH_STENCIL_DESC depthDesc = {};
  depthDesc.DepthEnable = TRUE;
  depthDesc.DepthWriteMask = D3D12_DEPTH_WRITE_MASK_ALL; // 禁止写入深度
  depthDesc.DepthFunc = D3D12_COMPARISON_FUNC_ALWAYS;    // 始终通过测试
  particle_desc.DepthStencilState = depthDesc;
  // 粒子系统使用和常规对象一样的顶点输入。
  particle_desc.InputLayout = {
      input_layout_.data(), (UINT)input_layout_.size()};

  HASSERT(dx_->Device()->CreateGraphicsPipelineState(
      &particle_desc, IID_PPV_ARGS(&pipelines_["Particle"])));

  //
  // 用于Particle（粒子）的MESH项目（拥有贴图）
  //
  D3D12_GRAPHICS_PIPELINE_STATE_DESC particle_mesh_desc = particle_desc;
  particle_mesh_desc.pRootSignature = dx_->GetRootsign().mParticle.Get();
  particle_mesh_desc.VS = SHADERS_ARGS_(PARTICLE_MESH_VS);
  particle_mesh_desc.PS = SHADERS_ARGS_(PARTICLE_MESH_PS);
  HASSERT(dx_->Device()->CreateGraphicsPipelineState(
      &particle_mesh_desc, IID_PPV_ARGS(&pipelines_["ParticleMesh"])));

  //
  // 用于绘制线段
  //
  D3D12_GRAPHICS_PIPELINE_STATE_DESC particle_line_desc = particle_desc;
  particle_line_desc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_LINE;
  particle_line_desc.VS = SHADERS_ARGS_(PARTICLE_LINE_VS);
  particle_line_desc.PS = SHADERS_ARGS_(PARTICLE_LINE_PS);
  auto& rs = particle_line_desc.RasterizerState;
  rs.FillMode = D3D12_FILL_MODE_SOLID; // 实线模式
  rs.CullMode = D3D12_CULL_MODE_NONE;  // 禁用剔除（双面线段）
  rs.AntialiasedLineEnable = TRUE;     // 启用线段抗锯齿
  HASSERT(dx_->Device()->CreateGraphicsPipelineState(
      &particle_line_desc, IID_PPV_ARGS(&pipelines_["ParticleLine"])));
}

void DxPipeline::CreateAlpha() {
  D3D12_GRAPHICS_PIPELINE_STATE_DESC alpha_desc = opaque_desc;
  D3D12_RENDER_TARGET_BLEND_DESC alpha_trans{};
  alpha_trans.BlendEnable = true;
  alpha_trans.LogicOpEnable = false;

  alpha_trans.SrcBlend = D3D12_BLEND_SRC_ALPHA;
  alpha_trans.DestBlend = D3D12_BLEND_INV_SRC_ALPHA;
  alpha_trans.BlendOp = D3D12_BLEND_OP_ADD;

  alpha_trans.SrcBlendAlpha = D3D12_BLEND_ONE;
  alpha_trans.DestBlendAlpha = D3D12_BLEND_INV_SRC_ALPHA;
  alpha_trans.BlendOpAlpha = D3D12_BLEND_OP_ADD;
  alpha_trans.RenderTargetWriteMask = D3D12_COLOR_WRITE_ENABLE_ALL;

  alpha_desc.BlendState.RenderTarget[0] = alpha_trans;
  HASSERT(dx_->Device()->CreateGraphicsPipelineState(
      &alpha_desc, IID_PPV_ARGS(&pipelines_["AlphaTransparent"])));

  // 用于透明的对象（蒙皮骨骼）,Alpha
  D3D12_GRAPHICS_PIPELINE_STATE_DESC skinned_alpha = alpha_desc;
  skinned_alpha.InputLayout = {
      skinned_input_layout_.data(), (UINT)skinned_input_layout_.size()};
  skinned_alpha.VS = SHADERS_ARGS_(SKINNED_VS);
  // 这里把项目丢弃，能够得到背面的东西
  skinned_alpha.PS = SHADERS_ARGS_(SKINNED_ALPHA_TEST_PS);

  // 因为SkinAlpha是用来画头发的（以后会单独搞Shader），所以不需要背面剔除
  // skinned_alpha.RasterizerState.CullMode = D3D12_CULL_MODE_NONE; //
  // 关键修改：禁用剔除
  HASSERT(dx_->Device()->CreateGraphicsPipelineState(
      &skinned_alpha, IID_PPV_ARGS(&pipelines_["SkinnedAlpha"])));
}

bool DxPipeline::IsContainShader(const char* key) const {
  // 空指针检查
  if (!key) return false;

  // 转换为string_view避免临时string对象
  std::string_view key_view(key);

  // 查找并验证有效性
  auto it = shaders_.find(key_view);
  return it != shaders_.end() && it->second != nullptr;
}

bool DxPipeline::IsContainPipeline(const char* key) const {
  // 空指针检查
  if (!key) return false;

  // 直接构造string_view
  std::string_view key_view(key);

  // 查找并验证非空
  auto it = pipelines_.find(key_view);
  return it != pipelines_.end() && it->second != nullptr;
}

ID3D12PipelineState* DxPipeline::operator[](const char* key) const {
  return pipelines_.at(std::string_view(key)).Get();
}

} // namespace ifire::dx